package com.stateflow.engine.core.serviceimpl;

import com.stateflow.facade.common.exception.CommonException;
import com.stateflow.facade.common.util.CommonAssert;
import com.stateflow.facade.common.util.HttpUtils;
import com.stateflow.facade.common.util.JsonUtils;
import com.stateflow.facade.common.util.StringUtils;
import com.stateflow.engine.core.cache.StateFlowCache;
import com.stateflow.facade.dto.OperatorDTO;
import com.stateflow.facade.dto.receive.NotifyReceiveDTO;
import com.stateflow.facade.dto.req.StateFlowRequestDTO;
import com.stateflow.facade.dto.StateFlowConfigDTO;
import com.stateflow.facade.dto.notify.StateFlowNotifyDTO;
import com.stateflow.facade.enums.NotifyReceiveEnum;
import com.stateflow.engine.core.service.StateFlowCoreService;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * Created by weiqingming on 2019/11/28.
 * 状态流转核心
 */
@Service("stateFlowCoreService")
public class StateFlowCoreServiceImpl implements StateFlowCoreService {


    @Override
    public StateFlowNotifyDTO stateFlow(StateFlowRequestDTO request, StateFlowConfigDTO config) {

        CommonAssert.isNoEmptyCollection(config.getStateFlows(),"尚未配置状态流转模型");

        // 获取转换好的模型，查找的时间复杂度为O(1)
        Map<String, Map<String, OperatorDTO>> flowMap = StateFlowCache.get(config);

        // 取出操作
        Map<String, OperatorDTO> operatorMap = flowMap.get(request.getCurrentState());
        CommonAssert.isNoEmptyObj(operatorMap,"此状态还未配置操作");
        OperatorDTO operator = operatorMap.get(request.getOperatorCode());
        CommonAssert.isNoEmptyObj(operator,"此状态下没有配置该操作");

        // 组装通知的数据
        StateFlowNotifyDTO notify = new StateFlowNotifyDTO();
        notify.setOrderNumber(request.getOrderNumber());
        notify.setAttach(request.getAttach());
        notify.setOperatop(operator);

        //执行操作
        switch (operator.getNotifyType()) {

            case "HTTP":
                httpNotify(operator, notify);
                break;

            case "RPC":
                throw new CommonException("暂未支持RPC通知方式");

            case "NO_NOTIFY":
                break;
        }

        return notify;
    }


    @Override
    public List<OperatorDTO> listOperator(String state, StateFlowConfigDTO config) {

        CommonAssert.isNoEmptyCollection(config.getStateFlows(),"尚未配置状态流转模型");

        // 获取转换好的模型，查找的时间复杂度为O(1)
        Map<String, Map<String, OperatorDTO>> flowMap = StateFlowCache.get(config);
        Map<String, OperatorDTO> operators = flowMap.get(state);
        if (operators == null){
            return null;
        }

        // 遍历取出操作列表
        List<OperatorDTO> operatorList = new ArrayList<>();
        for (Map.Entry<String, OperatorDTO> item : operators.entrySet()) {
            operatorList.add(item.getValue());
        }

        return operatorList;
    }


    /**
     * HTTP类型的通知
     * @param operator
     * @param notify
     */
    private void httpNotify(OperatorDTO operator, StateFlowNotifyDTO notify) {

        // 发送请求与结果判断
        String resultJson = HttpUtils.sendHttpPost(operator.getNotifyUrl(), notify.toString());
        CommonAssert.isNoBlankStr(resultJson, "请求外部接口失败");
        NotifyReceiveDTO notifyReceive = JsonUtils.toObject(resultJson, NotifyReceiveDTO.class);
        CommonAssert.isNoEmptyObj(notifyReceive, "请求外部接口返回数据异常");
        boolean success = StringUtils.equals(notifyReceive.getReturnCode(), NotifyReceiveEnum.SUCCESS.getCode());
        CommonAssert.isTrue(success, "外部接口处理失败 - " + notifyReceive.getReturnMsg());
    }

}
